<?php
defined( 'BASEPATH' ) or exit( 'No direct script access allowed' );
class MySession implements SessionHandlerInterface
{
    private static $_instance = null;
    private $_config = array (
            'table_name' => 'sessions',
            'session_name' => '',
            'lifetime' => 1200 
    );
    private $_db = null;
    private $_lock = '';
    private function __construct($config)
    {
        if (is_array( $config ))
        {
            foreach ( $config as $k => $v )
            {
                $k = strtolower( $k );
                if (isset( $this->_config[$k] ))
                {
                    $this->_config[$k] = $v;
                }
            }
        }
        if (! class_exists( 'MyPDO', false ))
        {
            exit( 'Not found mysql driver' );
        }
        $this->_db = MyPDO::get_instance();
        
        if (! empty( $this->_config['session_name'] ))
        {
            ini_set( 'session.name', $this->_config['session_name'] );
        }
        $session_name = ini_get( 'session.name' );
        if (isset( $_COOKIE[$session_name] ) && (! is_string( $_COOKIE[$session_name] ) || ! preg_match( '/^[0-9a-z]{24,40}$/', $_COOKIE[$session_name] )))
        {
            unset( $_COOKIE[$session_name] );
        }
        
        session_set_save_handler( $this, true );
    }
    private function __clone()
    {
    }
    /**
     * 保证“唯一”请求ID
     *
     * @return MysqlLog
     */
    public static function get_instance($config = array())
    {
        if (! isset( self::$_instance ))
        {
            self::$_instance = new self( $config );
        }
        if (session_status() !== PHP_SESSION_ACTIVE)
        {
            session_start();
        }
        if (class_exists( 'MyLog', false ))
        {
            MyLog::get_instance()->set_session();
        }
        return self::$_instance;
    }
    function open($save_path, $name)
    {
        return ( bool ) $this->_db->get_connecttion();
    }
    function read($session_id)
    {
        if ($this->get_lock( $session_id ))
        {
            $this->_db->select( $this->_config['table_name'], '`session_data`', 'session_id=? and session_expire>?', array (
                    $session_id,
                    $_SERVER['REQUEST_TIME'] 
            ) );
            if ($result = $this->_db->fetch_row())
            {
                return $result['session_data'];
            }
        }
        return '';
    }
    function gc($maxlifetime)
    {
        $this->_db->delete( $this->_config['table_name'], 'session_expire<?', $_SERVER['REQUEST_TIME'] );
        return $this->_db->execute();
    }
    function write($session_id, $session_data)
    {
        $this->_db->replace( $this->_config['table_name'], array (
                'session_id' => $session_id,
                'session_data' => $session_data,
                'session_expire' => $_SERVER['REQUEST_TIME'] + $this->_config['lifetime'] 
        ) );
        return $this->_db->execute();
    }
    function destroy($session_id)
    {
        $setting = session_get_cookie_params();
        setcookie( ini_get( 'session.name' ), null, 0, $setting['path'], $setting['domain'], $setting['secure'], $setting['httponly'] );
        $this->_db->delete( $this->_config['table_name'], 'session_id=?', $session_id );
        return $this->_db->execute();
    }
    function close()
    {
        return $this->release_lock();
    }
    private function get_lock($key)
    {
        if ($this->_db->query( "SELECT GET_LOCK('" . $key . "', 300) AS session_lock" )->execute())
        {
            $this->_lock = $key;
            return true;
        }
        return false;
    }
    private function release_lock()
    {
        if (! $this->_lock)
        {
            return true;
        }
        if ($this->_db->query( "SELECT RELEASE_LOCK('" . $this->_lock . "') AS session_lock" )->execute())
        {
            $this->_lock = '';
            return true;
        }
        return false;
    }
}

